﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SPListHelper.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Provides common utilities for interacting with SharePoint lists.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.DataAccess.SharePoint
{
    #region Imports

    using System;
    using System.Globalization;
    using System.IO;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;



    #endregion

    /// <summary>
    /// Provides common utilities for interacting with SharePoint lists.
    /// </summary>
    public static class SPListHelper
    {
        /// <summary>
        /// Adds the specified <paramref name="file"/> to the root folder of the
        /// given <paramref name="list">list.</paramref>.
        /// </summary>
        /// <param name="file">
        /// The file to upload.
        /// </param>
        /// <param name="list">
        /// The destination list.
        /// </param>
        public static void AddFile(FileSystemInfo file, SPList list)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            if (list == null)
            {
                throw new ArgumentNullException("list");
            }

            AddFileToList(file, list.RootFolder);
        }

        /// <summary>
        /// Adds the specified <paramref name="file"/> to the specified <paramref name="folder"/> of the
        /// given <paramref name="list">list.</paramref>.
        /// </summary>
        /// <param name="file">
        /// The file to upload.
        /// </param>
        /// <param name="list">
        /// The destination list.
        /// </param>
        /// <param name="folder">
        /// The folder to add the file to.
        /// </param>
        /// <param name="contentTypeName">
        /// Name of the content type for this document.
        /// </param>
        public static void AddFile(FileSystemInfo file, SPList list, SPFolder folder, string contentTypeName)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }

            SPFile sharepointFile = AddFileToList(file, folder);
            sharepointFile.Item["ContentTypeId"] = list.ContentTypes[contentTypeName].Id;
            sharepointFile.Item.Update();
        }

        /// <summary>
        /// Adds a file to the specified <paramref name="folder"/>.
        /// </summary>
        /// <param name="file">
        /// The file to add.
        /// </param>
        /// <param name="folder">
        /// The folder to add the file to.
        /// </param>
        /// <returns>
        /// The newly added file.
        /// </returns>
        private static SPFile AddFileToList(FileSystemInfo file, SPFolder folder)
        {
            SPFile newFile = folder.Files.Add(file.Name, File.ReadAllBytes(file.FullName));
            newFile.Update();

            return newFile;
        }

        /// <summary>
        /// Tries to get a list from an SPWeb. It returns null if the list does not exist.
        /// </summary>
        /// <param name="web">
        /// SPWeb containing the Lists collection.
        /// </param>
        /// <param name="listName">
        /// string Name of the list
        /// </param>
        /// <returns>
        /// SPList object or null if the list does not exist
        /// </returns>
        public static SPList TryGetList(SPWeb web, string listName)
        {
            Utils.VerifyObjectArgument(web, "web");
            Utils.VerifyStringArgument(listName, "listName");

            try
            {
                SPList list = web.Lists[listName];
                return list;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Gets a list from an SPWeb. It throws a meaningfull error if the list does not exist.
        /// </summary>
        /// <param name="web">
        /// SPWeb containing the Lists collection.
        /// </param>
        /// <param name="listName">
        /// string Name of the list
        /// </param>
        /// <returns>
        /// true if it does exits; otherwise false.
        /// </returns>
        public static SPList GetList(SPWeb web, string listName)
        {
            Utils.VerifyObjectArgument(web, "web");
            Utils.VerifyStringArgument(listName, "listName");

            SPList list = TryGetList(web, listName);
            if (list == null)
            {
                throw new ArgumentException("Exception in trying to get list with name: '" + listName + "' from web '" + web.Title + "'");
            }

            return list;
        }

        /// <summary>
        /// Check if a list exists (unfortunatelly the only way to do this is to try to get the list)
        /// </summary>
        /// <param name="web">
        /// </param>
        /// <param name="listName">
        /// </param>
        public static void EnsureListExists(SPWeb web, string listName)
        {
            GetList(web, listName);
        }

        /// <summary>
        /// Ensures that the espcified field exists on a list. 
        /// It throws a meaningfull exception if the field doesn't exist
        /// instead of the usual SP "Value does not fall withing expected range" exception)
        /// </summary>
        /// <param name="list">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        public static void EnsureFieldExists(SPList list, string fieldName)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }

            if (!list.Fields.ContainsField(fieldName))
            {
                string errorMsg = String.Format(CultureInfo.CurrentCulture, "List {0} does not contain field named {1}", list.Title, fieldName);
                Console.WriteLine(errorMsg);
                throw new ArgumentOutOfRangeException(errorMsg);
            }
        }

        /// <summary>
        /// The ensure field exists.
        /// </summary>
        /// <param name="web">
        /// The web.
        /// </param>
        /// <param name="listName">
        /// The list name.
        /// </param>
        /// <param name="fieldName">
        /// The field name.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// </exception>
        public static void EnsureFieldExists(SPWeb web, string listName, string fieldName)
        {
            if (web == null)
            {
                throw new ArgumentNullException("web");
            }

            SPList list = GetList(web, listName);
            EnsureFieldExists(list, fieldName);
        }

        /// <summary>
        /// The ensure field exists.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        /// <param name="fieldName">
        /// The field name.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// </exception>
        public static void EnsureFieldExists(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (!item.Fields.ContainsField(fieldName))
            {
                string errorMsg = String.Format(CultureInfo.CurrentCulture, 
                                                "List {0} does not contain field named {1}", 
                                                item.ParentList.Title, 
                                                fieldName);
                Console.WriteLine(errorMsg);
                throw new ArgumentOutOfRangeException(errorMsg);
            }
        }

        /// <summary>
        /// Safelly gets the string value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column string value.
        /// </returns>
        public static string GetColumnStringValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return obj.ToString();
            }

            return String.Empty;
        }

        /// <summary>
        /// Safelly gets the string value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The try get column string value.
        /// </returns>
        public static string TryGetColumnStringValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            // If item does not contain field then return null
            if (!item.Fields.ContainsField(fieldName))
            {
                return String.Empty;
            }

            object obj = item[fieldName];

            if (obj != null)
            {
                return obj.ToString();
            }

            return String.Empty;
        }

        /// <summary>
        /// Safelly gets the int value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column int value.
        /// </returns>
        public static int GetColumnIntValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToInt32(obj);
            }

            return 0;
        }

        /// <summary>
        /// Safelly gets the int value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column int value.
        /// </returns>
        public static Int64 GetColumnLongValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToInt64(obj);
            }

            return 0;
        }

        /// <summary>
        /// Safelly gets the double value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column double value.
        /// </returns>
        public static double GetColumnDoubleValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToDouble(obj);
            }

            return 0;
        }

        /// <summary>
        /// Safelly gets the double value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column double value.
        /// </returns>
        public static double GetCalculatedColumnDoubleValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToDouble(obj.ToString().ToLower().Replace(@"float;#", String.Empty));
            }

            return 0;
        }

        /// <summary>
        /// Safelly gets the datetime value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column datetime value.
        /// </returns>
        public static DateTime GetColumnDateTimeValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToDateTime(obj.ToString());
            }

            return new DateTime(SPUtility.GetCalendarYearMin((int)SPCalendarType.Gregorian), 1, 1);
        }

        /// <summary>
        /// Safelly gets the datetime value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column datetime value.
        /// </returns>
        public static DateTime? GetNullableColumnDateTimeValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            if (obj != null)
            {
                return Convert.ToDateTime(obj.ToString());
            }

            return null;
        }

        public static SPFieldUrlValue GetColumnUrlValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            SPFieldUrlValue obj = item[fieldName] as SPFieldUrlValue;

            if (obj != null)
            {
                return obj;
            }

            return null;
        }

        /// <summary>
        /// Tries to get the value of a SPListItem colum. Returns the default for the epscified type
        /// if field does not exist.
        /// </summary>
        /// <typeparam name="T">
        /// </typeparam>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// </returns>
        public static T TryGetColumnValue<T>(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            // If item does not contain field then return null
            if (!item.Fields.ContainsField(fieldName))
            {
                return default(T);
            }

            object obj = item[fieldName];

            if (obj == null)
            {
                return default(T);
            }

            return (T)Convert.ChangeType(obj, typeof(T));
        }

        /// <summary>
        /// Safelly gets the int value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// </returns>
        public static bool GetColumnBoolValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            object obj = item[fieldName];

            return Convert.ToBoolean(obj);
        }

        /// <summary>
        /// Safelly gets the object value of a SPListItem colum.
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column value.
        /// </returns>
        public static object GetColumnValue(SPListItem item, string fieldName)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            return item[fieldName];
        }

        /// <summary>
        /// Safelly gets the Field details of a SPList.
        /// </summary>
        /// <param name="list">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// </returns>
        public static SPField GetField(SPList list, string fieldName)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }

            if (String.IsNullOrEmpty(fieldName))
            {
                throw new ArgumentNullException("fieldName");
            }

            EnsureFieldExists(list, fieldName);

            return list.Fields[fieldName];
        }

        /// <summary>
        /// Safelly sets the value of a list item
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <param name="value">
        /// </param>
        public static void SetColumnValue(SPListItem item, string fieldName, object value)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            item[fieldName] = value;
        }

        /// <summary>
        /// Safelly sets the value of a list item
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <param name="value">
        /// </param>
        public static void SetColumnUrlValue(SPListItem item, string fieldName, SPFieldUrlValue value)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            item[fieldName] = value;
        }

        /// <summary>
        /// Safelly sets the value of a list item
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <param name="value">
        /// </param>
        public static void SetColumnDateTimeValue(SPListItem item, string fieldName, object value)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            EnsureFieldExists(item, fieldName);

            item[fieldName] = value == null ? System.DBNull.Value : value;
        }

        /// <summary>
        /// Checks if a list item is approved
        /// </summary>
        /// <param name="item">
        /// </param>
        /// <returns>
        /// The item is approved.
        /// </returns>
        public static bool ItemIsApproved(SPListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (item["_ModerationStatus"] != null && item["_ModerationStatus"].ToString() == "0")
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Safelly gets the string value of a properties colum.
        /// </summary>
        /// <param name="properties">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column string value.
        /// </returns>
        public static string GetColumnStringValue(SPItemEventDataCollection properties, string fieldName)
        {
            if (properties == null)
            {
                throw new ArgumentNullException("properties");
            }

            // EnsureFieldExists(item, fieldName);
            object obj = properties[fieldName];

            if (obj != null)
            {
                return obj.ToString();
            }

            return String.Empty;
        }

        /// <summary>
        /// Safelly gets the int value of a SPListItem colum.
        /// </summary>
        /// <param name="properties">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The get column int value.
        /// </returns>
        public static int GetColumnIntValue(SPItemEventDataCollection properties, string fieldName)
        {
            // EnsureFieldExists(item, fieldName);
            if (properties == null)
            {
                throw new ArgumentNullException("properties");
            }

            object obj = properties[fieldName];

            if (obj != null)
            {
                return Convert.ToInt32(obj);
            }

            return 0;
        }
    }
}